package com.bluexmicro.bluetooth.peripheral.handler

import android.annotation.SuppressLint
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattDescriptor
import com.bluexmicro.bluetooth.LogUtils
import com.bluexmicro.bluetooth.model.GattStatus
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

typealias ReadDescriptorCallback = (
    gatt: BluetoothGatt,
    descriptor: BluetoothGattDescriptor,
    value: ByteArray,
    status: Int
) -> Unit

class ReadDescriptorHandler {

    private var callback: ReadDescriptorCallback? = null
    private var cancellableContinuation: CancellableContinuation<Result<ByteArray>>? = null

    fun onDescriptorRead(
        gatt: BluetoothGatt,
        descriptor: BluetoothGattDescriptor,
        value: ByteArray,
        status: Int
    ) {
        callback?.invoke(gatt, descriptor, value, status)
    }

    private fun setCallback(cb: ReadDescriptorCallback) {
        this.callback = cb
    }

    fun isActive(): Boolean {
        return cancellableContinuation?.isActive == true
    }

    @SuppressLint("MissingPermission")
    suspend fun execute(
        gatt: BluetoothGatt,
        descriptor: BluetoothGattDescriptor,
    ) = suspendCancellableCoroutine<Result<ByteArray>> {
        cancellableContinuation = it
        setCallback { _, d, value, status ->
            if (d.uuid.equals(descriptor.uuid)) {
                this.callback = null
                if (it.isActive) {
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        it.resume(Result.success(value))
                    } else {
                        val reason = GattStatus.fromValue(status).name
                        it.resume(Result.failure(IllegalStateException("Read descriptor Failed, gatt status: $status, reason: $reason")))
                    }
                }
            }
        }
        val res = !gatt.readDescriptor(descriptor)
        LogUtils.sendLog(
            mapOf(
                "mac" to gatt.device.address,
                "call method" to "readDescriptor",
                "service" to descriptor.characteristic.service.uuid.toString(),
                "characteristic" to descriptor.characteristic.uuid.toString(),
                "descriptor" to descriptor.uuid.toString(),
                "detail" to if (res) "sent" else "failed"
            )
        )

        if (!res) {
            this.callback = null
            if (it.isActive) {
                it.resume(Result.failure(Throwable("Read descriptor Failed!")))
            }
        }

        it.invokeOnCancellation {
            this.callback = null
        }
    }
}